<?php

namespace app\utils;

use think\facade\Session;
use think\facade\Cookie;
use think\facade\Db;
use think\facade\Cache;
use app\model\User;
use think\facade\Request;

class Utils
{
    public static function is_user_logined()
    {
        $email = Session::get('email', '');
        $password = Session::get('password', '');

        if (!$email) {
            return false;
        }
        if (!$password) {
            return false;
        }

        $user = User::where('email', $email)->select()->toArray(); // 查询数据

        if (count($user) == 0) { // 不存在
            return false;
        } else {
            if ($user[0]['password'] != $password) { // 对比数据
                return false;
            }
        }

        return true;
    }
    public static function getIp()
    {
        $ip = '0.0.0.0';
        if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
            $ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
        } elseif (!empty($_SERVER['HTTP_CLIENT_IP'])) {
            $ip = $_SERVER['HTTP_CLIENT_IP'];
        } else {
            $ip = $_SERVER['REMOTE_ADDR'];
        }
        return $ip;
    }

    public static function get_user_info($email)
    {
        // $data = Db::connect()->table('site_token')->where('token', $token)->select()->toArray();
        // if (count($data) == 0) return false;

        $user = User::where('email', $email)->select()->toArray()[0]; // 查询数据

        if (count($user) == 0) return false;
        return $user['id'];
    }

    public static function get_admin()
    {
        $email = Session::get('email', '');
        $password = Session::get('password', '');

        if (!$email) {
            return false;
        }
        if (!$password) {
            return false;
        }

        $user = User::where('email', $email)->select()->toArray(); // 查询数据

        if (count($user) == 0) { // 不存在
            return false;
        } else {
            if ($user[0]['password'] != $password) { // 对比数据
                return false;
            }
        }

        if ($user[0]['admin'] === "") {
            return false;
        }

        $jobs = json_decode($user[0]['admin']);

        $admin = array();
        foreach ($jobs as $job) {
            $value = Db::table('site_admin')->where('id', intval($job))->select()->toArray();
            $json = $value[0]['info'];
            if (!$json) {
                $json = "[]";
            }
            $admin = array_merge($admin, json_decode($json));
        }

        if (count($admin) == 0) {
            return false;
        }

        return $admin;
    }

    public static function has_admin($path)
    {
        $admin = Utils::get_admin();

        if ($admin === false) {
            return false;
        }

        if (in_array("super_admin", $admin)) return true;

        return in_array($path, $admin);
    }

    public static function make_img($code)
    {
        // 设置图片尺寸
        $width = 300;
        $height = 100;

        // 创建空白画布
        $image = imagecreatetruecolor($width, $height);

        // 创建背景颜色
        $bgColor = imagecolorallocate($image, 255, 255, 255);
        imagefill($image, 0, 0, $bgColor);

        // 添加随机干扰线条
        for ($i = 0; $i < rand(15, 25); $i++) {
            $lineColor = imagecolorallocate($image, rand(0, 200), rand(0, 200), rand(0, 200));
            imageline($image, mt_rand(0, $width), mt_rand(0, $height), mt_rand(0, $width), mt_rand(0, $height), $lineColor);
        }

        // 字母随机大小写
        $result = '';
        for ($i = 0; $i < strlen($code); $i++) {
            $char = $code[$i];
            if (ctype_alpha($char)) {
                $randomCase = mt_rand(0, 1) ? 'strtoupper' : 'strtolower';
                $result .= $randomCase($char);
            } else {
                $result .= $char;
            }
        }

        // 添加字符
        $x = 10;

        for ($i = 0; $i < 5; $i++) {
            $character = $result[$i];
            $color = imagecolorallocate($image, rand(0, 255), rand(0, 255), rand(0, 255));
            $font = 'arial.ttf'; // 字体文件路径，需要根据实际情况修改
            $size = rand(20, 40); // 字符大小
            $angle = rand(-20, 20); // 字符方向
            $x += rand(8, 23);
            $y = rand(35, $height - 5); // 字符y坐标
            imagettftext($image, $size, $angle, $x, $y, $color, $font, $character);
            $x += $size + rand(5, 10);
        }

        // 添加随机干扰点
        for ($i = 0; $i < rand(350, 450); $i++) {
            $pointColor = imagecolorallocate($image, rand(0, 255), rand(0, 255), rand(0, 255));
            imagesetpixel($image, mt_rand(0, $width - 1), mt_rand(0, $height - 1), $pointColor);
        }

        // 将图片转换为base64格式
        ob_start();
        imagepng($image);
        $image_data = ob_get_clean();
        $base64 = 'data:image/png;base64,' . base64_encode($image_data);
        imagedestroy($image);
        return $base64;
    }

    public static function markdownToHtml($markdown)
    {
        // 处理粗体 **text** 转换为 <strong>text</strong>
        $markdown = preg_replace('/\*\*(.*?)\*\*/s', '<strong>$1</strong>', $markdown);

        // 处理斜体 *text* 转换为 <em>text</em>
        $markdown = preg_replace('/\*(.*?)\*/s', '<em>$1</em>', $markdown);

        // 处理标题 # text 转换为 <h1>text</h1>
        $markdown = preg_replace('/\# (.*?)\n/', '<h1>$1</h1>', $markdown);
        // 处理标题 # text 转换为 <h2>text</h2>
        $markdown = preg_replace('/\#\# (.*?)\n/', '<h2>$1</h2>', $markdown);
        // 处理标题 # text 转换为 <h3>text</h3>
        $markdown = preg_replace('/\#\#\# (.*?)\n/', '<h3>$1</h3>', $markdown);
        // 处理标题 # text 转换为 <h4>text</h4>
        $markdown = preg_replace('/\#\#\#\# (.*?)\n/', '<h4>$1</h4>', $markdown);

        // 处理链接 [text](url "text") 转换为 <a href="url">text</a>
        $markdown = preg_replace('/\[(.*?)\]\((.*?) \"(.*?)\"\)/', '<a href="$2">$1</a>', $markdown);

        // 处理链接 [text](url) 转换为 <a href="url">text</a>
        $markdown = preg_replace('/\[(.*?)\]\((.*?)\)/', '<a href="$2">$1</a>', $markdown);

        // 处理代码块 `code` 转换为 <code>code</code>
        $markdown = preg_replace('/\`(.*?)\`/', '<code>$1</code>', $markdown);

        // 处理HTML实体字符
        $markdown = preg_replace('/\&#64\;/', '@', $markdown); //@
        $markdown = preg_replace('/\&copy\;/', '©', $markdown); //©

        // 处理列表 * item 转换为 <li>item</li>
        $markdown = preg_replace('/^\* (.*?$)\n/m', '<li>$1</li>', $markdown);
        $markdown = "<ul>\n" . $markdown . "</ul>";

        return $markdown;
    }

    public static function markdownToText($markdown)
    {
        // 标题
        $markdown = preg_replace('/^#{1,6} (.*?$)$/m', '$1', $markdown);

        // 无序列表
        $markdown = preg_replace('/^\* (.*?$)\n/m', '$1', $markdown);
        $markdown = preg_replace('/^\- (.*?$)\n/m', '$1', $markdown);

        $markdown = preg_replace('/\`(.*?$)\`/s', '$1', $markdown); // 代码块
        $markdown = preg_replace('/^\-\-\-+$/m', '', $markdown); // 分割线
        $markdown = preg_replace('/^\[========+\]$/m', '', $markdown); // 分割线
        $markdown = preg_replace('/^\> (.*?$)\n$/m', '$1', $markdown); // 引用

        $markdown = preg_replace('/\!\[(.*?)\]\((.*?)\)/s', '', $markdown); // 图片
        $markdown = preg_replace('/\!\[(.*?)\]\((.*?) \"(.*?)\"\)/s', '', $markdown); // 图片

        $markdown = preg_replace('/\[(.*?)\]\((.*?)\)/s', '$1', $markdown); // 链接
        $markdown = preg_replace('/\[(.*?)\]\((.*?) \"(.*?)\"\)/s', '$1', $markdown); // 链接

        $markdown = preg_replace('/^\|(.*?)\|\n/m', '$1', $markdown); // 表格

        // 粗体/斜体/删除线
        $markdown = preg_replace('/\*\*\*(.*?)\*\*\*/s', '$1', $markdown);
        $markdown = preg_replace('/\*\*(.*?)\*\*/s', '$1', $markdown);
        $markdown = preg_replace('/\*(.*?)\*/s', '$1', $markdown);
        $markdown = preg_replace('/\_\_\_(.*?)\_\_\_/s', '$1', $markdown);
        $markdown = preg_replace('/\_\_(.*?)\_\_/s', '$1', $markdown);
        $markdown = preg_replace('/\_(.*?)\_/s', '$1', $markdown);
        $markdown = preg_replace('/\~\~(.*?)\~\~/s', '$1', $markdown);

        // 去换行
        $markdown = preg_replace('/\n/', '', $markdown);

        return $markdown;
    }

    public static function send_message($user_id, $time, $from_user_id, $text)
    {
        $data = ['user_id' => $user_id, 'from_user_id' => $from_user_id, 'text' => $text, 'time' => $time];
        Db::name('site_message')->save($data);
    }

    public static function write_log($user_id, $text) {}

    /**
     * 返回用户数组 / 未登录模板
     */
    public static function user(string $email, string $pw): array
    {
        /* --- 未登录模板 --- */
        $guest = [
            'name'  => '未登录',
            'img'   => 'https://creation.codemao.cn/716/appcraft/IMAGE_U53LlVovA_1693015896678.png',
            'email' => '',
            'id'    => '',
        ];

        /* --- 参数空 --- */
        if ($email === '' || $pw === '') {
            return $guest;
        }

        /* --- 用户是否存在 --- */
        $user = User::where('email', $email)->find();
        if (!$user || $user['password'] !== $pw) {
            return $guest;
        }

        /* --- UA 一致性 --- */
        if (Request::header('user-agent') !== Session::get('ua', '')) {
            return $guest;
        }

        /* --- 账号冻结 --- */
        if (Cache::get(md5('uid_' . $user['id']))) {
            return $guest;
        }

        /* --- token 存在且有效 --- */
        $token = Db::table('site_token')->where('token', Cookie::get('PHPSESSID'))->find();
        if (!$token || $token['bad'] == 1) {
            // 清理坏令牌
            Session::clear();
            @unlink('../runtime/session/sess_' . $token['token']);
            Db::table('site_token')->where('id', $token['id'])->delete();
            Cookie::delete('PHPSESSID');
            return $guest;
        }

        /* --- 刷新 token 时间 --- */
        Db::name('site_token')
            ->where('token', Cookie::get('PHPSESSID'))
            ->update(['time' => time(), 'ip' => self::getIp()]);

        return $user->toArray();   // 登录成功
    }

    public static function check_again($id)
    {
        if (!$id) {
            $code = 403;
            $data = null;
            $msg = "参数错误";
            return array('code' => $code, 'msg' => $msg);
        } else {
            $answer = Cache::get($id, false);
            if (!$answer) { // 不存在数据
                $code = 404;
                $data = null;
                $msg = "数据已过期或传输ID错误";
                return array('code' => $code, 'msg' => $msg);
            } else {
                if ($answer['status']) { // 已验证
                    $code = 200;
                    $data = null;
                    $msg = "验证成功";
                    return array('code' => $code, 'msg' => $msg);
                } else {
                    Cache::delete($id); // 删除缓存，防止爆破
                    $code = 403;
                    $data = null;
                    $msg = "";
                    return array('code' => $code, 'msg' => $msg);
                }
            }
        }
    }

    public static function random_char($extend = "")
    {
        $letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
        $numbers = '0123456789';

        $num = 2;
        if ($extend !== "") $num = 3;
        $rand = rand(1, $num);

        $char = "";
        if ($rand == 1) {
            $char = $letters[rand(0, strlen($letters) - 1)];
        } elseif ($rand == 2) {
            $char = $numbers[rand(0, strlen($numbers) - 1)];
        } elseif ($rand == 3) {
            $char = $extend[rand(0, strlen($extend) - 1)];
        }

        return $char;
    }
    public static function bcm_login($identity, $password)
    {
        $url = "https://api.codemao.cn/tiger/v3/web/accounts/login";
        $data = array(
            "pid" => "65edCTyg",
            "identity" => $identity,
            "password" => $password
        );

        $ch = curl_init();

        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_HTTPHEADER, array(
            'Content-Type: application/json;charset=UTF-8'
        ));

        $response = curl_exec($ch);
        $result = json_decode($response, true);

        curl_close($ch);

        return $response;
    }

    public static function api_response($code, $msg, $data = null)
    {
        $res = array(
            "code" => $code,
            "msg" => $msg,
        );
        if ($data) $res["data"] = $data;
        return json($res);
    }

    public static function en_emoji($text)
    {
        $escapedText = '';
        $length = mb_strlen($text, 'UTF-8');

        for ($i = 0; $i < $length; $i++) {
            $char = mb_substr($text, $i, 1, 'UTF-8');
            if (strlen($char) === 4) {
                $escapedText .= '&#x' . strtoupper(bin2hex(iconv('UTF-8', 'UCS-4BE', $char))) . ';';
            } else {
                $escapedText .= $char;
            }
        }

        return $escapedText;
    }

    public static function html_entity_to_emoji($text)
    {
        return preg_replace_callback('/&#[xX]0*([0-9a-fA-F]+);/', function ($matches) {
            $codepoint = hexdec($matches[1]);
            return html_entity_decode("&#$codepoint;", 0, 'UTF-8');
        }, $text);
    }
    public static function getCurrentUser()
    {
        $email = Session::get('email', '');
        $password = Session::get('password', '');

        if (!$email) {
            return false;
        }
        if (!$password) {
            return false;
        }

        $user = User::where('email', $email)->select()->toArray(); // 查询数据

        if (count($user) == 0) { // 不存在
            return false;
        } else {
            if ($user[0]['password'] != $password) { // 对比数据
                return false;
            }
        }

        return $user[0];
    }

    /**
     * 获取用户所属的小组树状结构
     * @param int $user_id 用户ID
     * @return array|bool 树状结构数组或false
     */
    public static function getUserGroupTree($user_id)
    {
        // 获取用户所属的所有小组
        $groupList = Db::name('site_user_group_user_list')->where('user_id', $user_id)->select();
        if (count($groupList) == 0) return false;
        
        $tree = array();
        $visitedGroups = array(); // 用于记录已处理过的小组，避免重复
        
        foreach ($groupList as $item) {
            $group_id = $item['group_id'];
            
            // 如果该小组已经处理过，跳过
            if (isset($visitedGroups[$group_id])) continue;
            
            // 获取小组信息
            $groupInfo = Db::name('site_user_group')->where('id', $group_id)->find();
            if (!$groupInfo) continue;
            
            // 记录为已访问
            $visitedGroups[$group_id] = true;
            
            // 获取该小组的父节点链
            $parentChain = self::getGroupParentChain($group_id);
            
            // 将父节点链添加到树中
            $currentPosition = &$tree;
            foreach ($parentChain as $parentGroup) {
                $parentId = $parentGroup['id'];
                if (!isset($currentPosition[$parentId])) {
                    $currentPosition[$parentId] = $parentGroup;
                    $currentPosition[$parentId]['children'] = array();
                    $visitedGroups[$parentId] = true;
                }
                $currentPosition = &$currentPosition[$parentId]['children'];
            }
            
            // 获取该小组的所有子节点
            $children = self::getGroupChildren($group_id);
            $groupInfo['children'] = $children;
            
            // 将当前小组添加到对应的位置
            $currentPosition[$group_id] = $groupInfo;
        }
        
        return $tree;
    }
    
    /**
     * 获取小组的父节点链
     * @param int $group_id 小组ID
     * @return array 父节点链数组
     */
    private static function getGroupParentChain($group_id)
    {
        $chain = array();
        $currentId = $group_id;
        
        while (true) {
            $group = Db::name('site_user_group')->where('id', $currentId)->find();
            if (!$group || $group['father_id'] == 0) break;
            
            $parent = Db::name('site_user_group')->where('id', $group['father_id'])->find();
            if (!$parent) break;
            
            // 将父节点插入到数组开头，形成从根到当前节点的链
            array_unshift($chain, $parent);
            $currentId = $group['father_id'];
        }
        
        return $chain;
    }
    
    /**
     * 递归获取小组的所有子节点
     * @param int $group_id 小组ID
     * @return array 子节点树状数组
     */
    private static function getGroupChildren($group_id)
    {
        $children = array();
        
        // 获取直接子节点
        $directChildren = Db::name('site_user_group')->where('father_id', $group_id)->select();
        
        foreach ($directChildren as $child) {
            $childId = $child['id'];
            // 递归获取子节点的子节点
            $grandChildren = self::getGroupChildren($childId);
            $child['children'] = $grandChildren;
            $children[$childId] = $child;
        }
        
        return $children;
    }
    
    /**
     * 获取分区树状结构
     * @param int $group_id 用户组ID
     * @return array|bool 分区树状结构数组或false
     */
    public static function getPartitionTree($group_id)
    {
        // 查询用户组有权限查看的分区
        $partitionRelations = Db::name('site_user_group_partition_post_list')
            ->where('type', 1) // type=1表示分区
            ->where('group_id', $group_id)
            ->select();
            
        if (count($partitionRelations) == 0) return false;
        
        $tree = array();
        $visitedPartitions = array(); // 用于记录已处理过的分区，避免重复
        
        foreach ($partitionRelations as $relation) {
            $partition_id = $relation['self_id'];
            
            // 如果该分区已经处理过，跳过
            if (isset($visitedPartitions[$partition_id])) continue;
            
            // 获取分区信息
            $partitionInfo = Db::name('site_post_partition')->where('id', $partition_id)->find();
            if (!$partitionInfo) continue;
            
            // 记录为已访问
            $visitedPartitions[$partition_id] = true;
            
            // 获取该分区的父节点链
            $parentChain = self::getPartitionParentChain($partition_id);
            
            // 将父节点链添加到树中
            $currentPosition = &$tree;
            foreach ($parentChain as $parentPartition) {
                $parentId = $parentPartition['id'];
                if (!isset($currentPosition[$parentId])) {
                    $currentPosition[$parentId] = $parentPartition;
                    $currentPosition[$parentId]['children'] = array();
                    $visitedPartitions[$parentId] = true;
                }
                $currentPosition = &$currentPosition[$parentId]['children'];
            }
            
            // 获取该分区的所有子节点
            $children = self::getPartitionChildren($partition_id);
            $partitionInfo['children'] = $children;
            
            // 将当前分区添加到对应的位置
            $currentPosition[$partition_id] = $partitionInfo;
        }
        
        return $tree;
    }
    
    /**
     * 获取分区的父节点链
     * @param int $partition_id 分区ID
     * @return array 父节点链数组
     */
    private static function getPartitionParentChain($partition_id)
    {
        $chain = array();
        $currentId = $partition_id;
        
        while (true) {
            $partition = Db::name('site_post_partition')->where('id', $currentId)->find();
            if (!$partition || $partition['father_id'] == 0) break;
            
            $parent = Db::name('site_post_partition')->where('id', $partition['father_id'])->find();
            if (!$parent) break;
            
            // 将父节点插入到数组开头，形成从根到当前节点的链
            array_unshift($chain, $parent);
            $currentId = $partition['father_id'];
        }
        
        return $chain;
    }
    
    /**
     * 递归获取分区的所有子节点
     * @param int $partition_id 分区ID
     * @return array 子节点树状数组
     */
    private static function getPartitionChildren($partition_id)
    {
        $children = array();
        
        // 获取直接子节点
        $directChildren = Db::name('site_post_partition')->where('father_id', $partition_id)->select();
        
        foreach ($directChildren as $child) {
            $childId = $child['id'];
            // 递归获取子节点的子节点
            $grandChildren = self::getPartitionChildren($childId);
            $child['children'] = $grandChildren;
            $children[$childId] = $child;
        }
        
        return $children;
    }
}
